package com.noble.glamour.module.logic.invoke;

import android.annotation.SuppressLint;
import android.app.Activity;

import com.alibaba.fastjson.JSON;
import com.noble.glamour.bean.center.user.detail.UserDetail;
import com.noble.glamour.module.logic.application.App;
import com.noble.glamour.module.logic.application.ModuleMgr;
import com.noble.glamour.module.logic.baseui.LoadingDialog;
import com.noble.glamour.module.logic.config.FinalKey;
import com.noble.glamour.module.util.ChineseFilter;
import com.noble.library.utils.JsonUtil;
import com.noble.glamour.module.util.UIShow;
import com.noble.glamour.ui.main.MainActivity;
import com.noble.library.dir.DirType;
import com.noble.library.host.Hosts;
import com.noble.library.log.PLogger;
import com.noble.library.log.PToast;
import com.noble.library.media.MediaUtil;
import com.noble.library.observe.MsgMgr;
import com.noble.library.utils.BitmapUtil;
import com.noble.library.utils.FileUtil;
import com.noble.meether.logic.media.MediaConstant;

import org.json.JSONArray;
import org.json.JSONObject;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.FlowableOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;

import static com.noble.glamour.module.logic.application.App.context;
import static com.noble.glamour.module.logic.application.ModuleMgr.getCenterMgr;

/**
 * CMD操作统一处理
 */
public class Invoker {
    // js cmd key
    public static final String JSCMD_refresh_web = "refresh_web";//主动调用刷新web页面

    private WebAppInterface appInterface = new WebAppInterface(context, null);
    private Object webView;

    /**
     * @return 获取持有的WebAppInterface实例
     */
    public WebAppInterface getWebAppInterface() {
        return appInterface;
    }

    //--------------------CMD处理start--------------------

    private static class SingletonHolder {
        public static Invoker instance = new Invoker();
    }

    public static Invoker getInstance() {
        return SingletonHolder.instance;
    }

    private Invoke invoke = new Invoke();

    /**
     * 根据command和data执行对应方法（处理在app内情况）
     *
     * @param appInterface WebAppInterface实例
     * @param cmd          CMD操作码
     * @param data         操作执行的json字符串数据
     */
    public void doInApp(WebAppInterface appInterface, final String cmd, final String data) {
        PLogger.d("---doInApp--->cmd：" + cmd + "，data：" + data +
                "，AppMgr.isForground()：" + App.isForeground());

        this.appInterface = (appInterface == null ? new WebAppInterface(context, null) : appInterface);
        webView = appInterface == null ? null : appInterface.getWebView();

        MsgMgr.getInstance().runOnUiThread(() -> {
            try {
                Method notifyCMDMethod = Invoke.class.getMethod(cmd, String.class);
                notifyCMDMethod.invoke(invoke, data);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * 本地调用执行JS逻辑
     *
     * @param cmd  JS cmd命令
     * @param data 传递给JS的数据
     */
    public void doInJS(String cmd, Map<String, Object> data) {
        Map<String, Object> cmdMap = new HashMap<>();
        cmdMap.put("jcmd", cmd);
        cmdMap.put("data", data == null ? new HashMap<>() : data);
        String url = "javascript:window.platform.appCommand('" + JSON.toJSONString(cmdMap) + "')";
        doInJS(url);
    }

    /**
     * 本地调用执行JS逻辑：特殊情况主动调用，如base64图片传输，无需转码
     *
     * @param callbackName   回调方法名
     * @param callbackID     回调id
     * @param responseString 调用传值
     * @param isTranscode    是否进行字符串转码
     */
    @SuppressLint("CheckResult")
    public void doInJS(final String callbackName, final String callbackID, final String responseString, final boolean isTranscode) {
        Flowable.create((FlowableOnSubscribe<String>) e -> {
            e.onNext(isTranscode ? ChineseFilter.toUnicode(responseString) : responseString);
            e.onComplete();
        }, BackpressureStrategy.BUFFER).subscribeOn(Schedulers.io()).
                observeOn(AndroidSchedulers.mainThread()).subscribe(s -> doInJS("javascript:" + callbackName + "(\'" + callbackID + "\',\'" + s + "\')"));
    }

    /**
     * 本地调用执行JS逻辑，默认进行字符串转码，以支持中文字符串的传输
     *
     * @param callbackName   回调方法名
     * @param callbackID     回调id
     * @param responseString 是否进行字符串转码
     */
    public void doInJS(String callbackName, String callbackID, String responseString) {
        doInJS(callbackName, callbackID, responseString, true);
    }

    /**
     * 本地调用执行JS逻辑
     *
     * @param loadUrl 调用执行的命令
     */
    public void doInJS(String loadUrl) {
        if (webView != null) {
            if (webView instanceof com.tencent.smtt.sdk.WebView) {
                ((com.tencent.smtt.sdk.WebView) webView).loadUrl(loadUrl);
                PLogger.d("---tencent x5--->" + loadUrl);
            } else if (webView instanceof android.webkit.WebView) {
                ((android.webkit.WebView) webView).loadUrl(loadUrl);
                PLogger.d("---webkit--->" + loadUrl);
            }
        }
    }

    /**
     * 设置webView，每次webView页面可见的时候重设
     *
     * @param webView WebView实例
     */
    public void setWebView(Object webView) {
        this.webView = webView;
        PLogger.d("------>" + String.valueOf(webView));
    }

    //--------------------CMD处理end--------------------

    public class Invoke {

        // 显示加载loading
        public void show_data_loading(String data) {
        }

        // 关闭加载loading
        public void hide_data_loading(String data) {
            PLogger.d("hide_data_loading: ------>" + data);
            LoadingDialog.closeLoadingDialog(500);
        }

        // 结束当前页面
        public void do_finish(String data) {
            PLogger.d("---do_finish--->" + data);
            Activity act = appInterface.getAct();
            if (act != null) act.finish();
        }

        // 侧滑出app页面
        public void jump_to_app(String data) {
            PLogger.d("---jump_to_app--->" + data);
            JSONObject dataObject = JsonUtil.getJsonObject(data);

            //跳转到应用内页面
            Activity act = appInterface.getAct();
            Activity context = (act == null ? (Activity) App.getActivity() : act);
            int code = dataObject.optInt("code");
            switch (code) {
                case 511://关于页面
                    UIShow.showAboutAct(context);
                    break;
                case 512://缘分吧主播管理规范
                    UIShow.showAnchorManage(context);
                    break;
                case 513://缘分吧平台规范
                    UIShow.showPlatformSpecific(context);
                    break;
                case 514://隐私政策
                    UIShow.showPrivacyPolicy(context);
                    break;
                case 515://用户注册协议
                    UIShow.showRegisterAgree(context);
                    break;
                case 516://交友注意事项
                    UIShow.showAppTips(context);
                    break;
                default:
                    break;
            }
        }

        // 屏幕震动
        public void play_shock(String data) {
            PLogger.d("---play_shock--->" + data);
            MediaUtil.vibrator(App.getContext());
        }

        // 加密网络请求
        public void safe_request(String data) {
            PLogger.d("---safe_request--->" + data);
            cmdRequest(JsonUtil.getJsonObject(data), true);
        }

        // 普通网络请求
        public void normal_request(String data) {
            PLogger.d("---normal_request--->" + data);
            cmdRequest(JsonUtil.getJsonObject(data), false);
        }

        // 切换到主tab页
        public void enter_tab(String data) {
            PLogger.d("---enter_tab--->" + data);
            JSONObject dataObject = JsonUtil.getJsonObject(data);
            // tab页面索引
            int index = 1;
            switch (dataObject.optInt("index")) {
                case 1:
                    index = FinalKey.MAIN_TAB_1;
                    break;
                case 2:
                    index = FinalKey.MAIN_TAB_2;
                    break;
                case 3:
                    index = FinalKey.MAIN_TAB_3;
                    break;
                case 4:
                    index = FinalKey.MAIN_TAB_4;
                    break;
                case 5:
                    index = FinalKey.MAIN_TAB_5;
                    break;
                default:
                    break;
            }
            Activity act = appInterface.getAct();
            if (act != null && act instanceof MainActivity) {
                ((MainActivity) act).changeTab(index);
            } else {
                UIShow.showMainWithTabData(act, index, null);
            }
        }

        // 获取设备信息
        public void getdevicemodel(String data) {
            PLogger.d("---getdevicemodel--->" + data);
            JSONObject dataObject = JsonUtil.getJsonObject(data);

            Map<String, Object> responseObject = new HashMap<>();
            responseObject.put("devicemodel", android.os.Build.MODEL);//解密后的服务端返回（安卓注意大小写）

            doInJS(dataObject.optString("callbackName"), dataObject.optString("callbackID"), JSON.toJSONString(responseObject));
        }

        // 吐司提示
        public void show_toast(String data) {
            PLogger.d("---show_toast--->" + data);
            JSONObject dataObject = JsonUtil.getJsonObject(data);
            PToast.showShort(dataObject.optString("content"));
        }

        // 刷新个人详情
        public void refresh_userdetail(String data) {
            PLogger.d("---refresh_userdetail--->" + data);
            getCenterMgr().reqMyInfo("Invoker.refresh_userdetail()");
        }

        // 照片选取：打开相册或相机，选取或拍摄完成之后回调图片的base64字符串给js(先进行图片质量压缩)
        public void get_image_data(String data) {
            PLogger.d("---get_image_data--->" + data);
            final JSONObject dataObject = JsonUtil.getJsonObject(data);
            Activity act = appInterface.getAct();
//            ImgSelectUtil.getInstance().pickPhotoGallery(act == null ? context : act, new ImgSelectUtil.OnChooseCompleteListener() {
//                @Override
//                public void onComplete(String... path) {
//                    if (path == null || path.length == 0 || TextUtils.isEmpty(path[0])) return;
//                    PLogger.d("------>" + path[0]);
//                    // 将选取的图片进行质量压缩并将二进制流转换为base64字符串
//                    Map<String, Object> responseObject = new HashMap<>();
//                    responseObject.put("imageData", BitmapUtil.imagePathToBase64(path[0]));//base64格式字符串
//                    doInJS(dataObject.optString("callbackName"), dataObject.optString("callbackID"), JSON.toJSONString(responseObject), false);
//                }
//            });
        }

        // 图片数据转换成url：将图片上传服务器，并回调图片服务器地址给js
        public void image_data_to_url(String data) {
            PLogger.d("---image_data_to_url--->" + data);
            final JSONObject dataObject = JsonUtil.getJsonObject(data);
            final List<String> files = new LinkedList<>();
            JSONArray imageDataList = JsonUtil.getJsonArray(dataObject.optString("imageDataList"));
            for (int i = 0; i < imageDataList.length(); i++) {
                files.add(BitmapUtil.saveBitmap(BitmapUtil.decodeBase64(imageDataList.optString(i)),
                        DirType.getUploadDir() + System.currentTimeMillis() + "_" + i + ".jpg"));//将base64的数据保存成jpg文件
            }
            // 图片上传，上传完成之后删除本地存储的缓存文件
            int type = dataObject.optInt("type");
            ModuleMgr.getMediaMgr().sendHttpMultiFiles(MediaConstant.UPLOAD_TYPE_PIC, 0, mediaUrls -> {
                Map<String, Object> responseObject = new HashMap<>();
                responseObject.put("urlList", mediaUrls.toArray());
                doInJS(dataObject.optString("callbackName"), dataObject.optString("callbackID"), JSON.toJSONString(responseObject));
                for (String s : files) FileUtil.deleteFile(s);
            }, (String[]) files.toArray(new String[files.size()]));
        }

        // 跳转到钻石购买页面
        public void jump_to_shop(String data) {
            PLogger.d("---jump_to_shop--->" + data);
            Activity act = appInterface.getAct();
            UIShow.showGoodsDiamondBottomDlg(act == null ? context : act);
        }

        // 联系qq客服
        public void open_qq_service(String data) {
            PLogger.d("---open_qq_service--->" + data);
            Activity act = appInterface.getAct();
            UIShow.showQQService(act == null ? context : act);
        }

        // 获取服务器请求url
        public void get_agent_url(String data) {
            PLogger.d("---get_agent_url--->" + data);
            JSONObject dataObject = JsonUtil.getJsonObject(data);

            String url = Hosts.HOST_URL;
            switch (dataObject.optString("type")) {
                case "go":
                    url = Hosts.FATE_IT_GO;
                    break;
                default:
                    break;
            }
            Map<String, Object> responseObject = new HashMap<>();
            responseObject.put("url", url);
            doInJS(dataObject.optString("callbackName"), dataObject.optString("callbackID"), JSON.toJSONString(responseObject));
        }

        // 获得用户自己的数据 （包含用户的账户余额等数据）
        public void get_user_detail(String data) {
            PLogger.d("---get_user_detail--->" + data);
            JSONObject dataObject = JsonUtil.getJsonObject(data);

            UserDetail userInfo = ModuleMgr.getCenterMgr().getMyInfo();
            Map<String, Object> responseObject = new HashMap<>();
            responseObject.put("uid", userInfo.getUid());
            responseObject.put("avatar", userInfo.getAvatar());
            responseObject.put("nickname", userInfo.getNickname());
            responseObject.put("gender", userInfo.getGender());
            responseObject.put("is_vip", userInfo.isVip());
            responseObject.put("diamond_count", userInfo.getDiamand());
            //此处实际上为versionName，h5字段定义偏差
            responseObject.put("version_code", ModuleMgr.getAppMgr().getVerName());
            doInJS(dataObject.optString("callbackName"), dataObject.optString("callbackID"), JSON.toJSONString(responseObject));
        }
    }

    /**
     * 游戏交互-请求转发，判断是否为go服务器接口进行url-hash加密，
     *
     * @param dataObject    JS传递的JSONObject
     * @param isSafeRequest 是否是加密请求
     */
    private void cmdRequest(final JSONObject dataObject, boolean isSafeRequest) {
        JSONObject bodyObject = JsonUtil.getJsonObject(dataObject.optString("body"));
        String url = dataObject.optString("url");
        ModuleMgr.getCommonMgr().CMDRequest(dataObject.optString("method"), isSafeRequest, url,
                ChineseFilter.JSONObjectToMap(bodyObject), response -> {
                    PLogger.d("---cmdRequest--->" + response.getResponseString());
                    doInJS(dataObject.optString("callbackName"), dataObject.optString("callbackID"), response.getResponseString());
                });
    }
}
